package com.atguigu.tingshu.payment.service.impl;

import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private WxPayV3Config wxPayV3Config;

    @Autowired
    private RSAAutoCertificateConfig rsaAutoCertificateConfig;


    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 创建微信支付订单
     *
     * @param paymentType 1301:下单 1302：充值
     * @return {timeStamp:"",package:"",paySign:"",signType:"",nonceStr:""}
     */
    @Override
    public Map<String, String> createJsapi(String paymentType, String orderNo) {
        //1.保存本地交易记录
        //1.1 获取或保存本地交易记录
        PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType, orderNo);

        //1.2 判断本地交易记录状态 支付状态：1401-未支付 1402-已支付
        String paymentStatus = paymentInfo.getPaymentStatus();
        if (SystemConstant.PAYMENT_STATUS_PAID.equals(paymentStatus)) {
            throw new RuntimeException("该订单已支付！");
        }

        //2.对接微信支付接口，获取微信拉起微信支付所需参数
        //2.1 创建调用微信支付JSAPI业务对象
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();

        //2.2 创建预下单参数请求对象
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        //测试付款金额固定硬编码为1分
        amount.setTotal(1);
        request.setAmount(amount);
        request.setAppid(wxPayV3Config.getAppid());
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setDescription(paymentInfo.getContent());
        request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
        //商户订单编号
        request.setOutTradeNo(orderNo);
        //小程序目前还未上线，仅支持应用下的开发者用户进行付款 故这里需要设置开发者用户的openid
        Payer payer = new Payer();
        payer.setOpenid("odo3j4qp-wC3HVq9Z_D9C0cOr0Zs");
        request.setPayer(payer);
        //2.3 调用微信获取response包含了调起支付所需的所有参数，可直接用于前端调起支付
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
        if (response != null) {
            String timeStamp = response.getTimeStamp();
            String nonceStr = response.getNonceStr();
            String packageVal = response.getPackageVal();
            String signType = response.getSignType();
            String paySign = response.getPaySign();
            Map<String, String> map = new HashMap<>();
            map.put("timeStamp", timeStamp);
            map.put("nonceStr", nonceStr);
            map.put("package", packageVal);
            map.put("signType", signType);
            map.put("paySign", paySign);
            return map;
        }
        return null;
    }

    /**
     * 查询订单支付状态
     *
     * @param orderNo
     * @return true:已支付  false:未支付
     */
    @Override
    public boolean queryPayStatus(String orderNo) {
       /* //1. 创建调用微信支付JSAPI业务对象
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();

        //2.创建查询交易订单参数请求对象
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setOutTradeNo(orderNo);
        //3.调用微信查询订单支付状态
        Transaction transaction = service.queryOrderByOutTradeNo(request);
        if (transaction != null) {
            Transaction.TradeStateEnum tradeState = transaction.getTradeState();
            log.info("查询订单支付状态：{}", tradeState.name());
            if (Transaction.TradeStateEnum.SUCCESS == tradeState) {
                Integer payerTotal = transaction.getAmount().getPayerTotal();
                if (payerTotal.intValue() == 1) {
                    return true;
                }
            }
        }
        return false;*/

        //1.模拟微信交易对象
        Transaction transaction = new Transaction();
        transaction.setOutTradeNo(orderNo);
        transaction.setTransactionId("wx" + IdUtil.getSnowflakeNextId());
        //2.直接处理核心业务
        paymentInfoService.updatePaymentInfo(transaction);
        return true;
    }

    /**
     * 微信支付成功后，微信会主动调用商户的回调接口，返回支付结果
     *
     * @param request
     * @return
     */
    @Override
    public void wxPaySuccessNotify(HttpServletRequest request) {
        log.info("微信支付成功回调");
        //1.验签签名（根据应用私钥进行验签）防止出现虚假通知，造成商户损失
        //1.1 从请求头中获取封装请求参数对象数据
        String signature = request.getHeader("Wechatpay-Signature");
        String serial = request.getHeader("Wechatpay-Serial");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String signaureType = request.getHeader("Wechatpay-Signature-Type");
        log.info("签名：{}，序列号：{}，随机数：{}，时间戳：{}，签名类型：{}", signature, serial, nonce, timestamp, signaureType);
        //1.2 获取请求体中参数
        String body = PayUtil.readData(request);
        log.info("请求体密文：{}", body);
        //2.参数解密：获取支付结果相关业务数据
        //2.1 构造RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(body)
                .build();
        //2.2 初始化 NotificationParser解析器对象
        NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
        //2.3 解密并转换成 Transaction交易对象
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        log.info("解密后交易结果：{}", transaction);
        if (transaction != null) {
            //3.幂等性保证
            //3.1 获取本次交易业务标识，可以选择微信交易订单号，或者选择商户侧订单编号
            String transactionId = transaction.getTransactionId();
            String key = "wxpay:notity:" + transactionId;
            //3.2 采用redis提供set nx命令，设置过期时间为25小时
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, transaction.getOutTradeNo(), 25, TimeUnit.HOURS);
            if (flag) {
                try {
                    //4.业务校验，验证支付状态以及支付金额
                    Transaction.TradeStateEnum tradeState = transaction.getTradeState();
                    if (Transaction.TradeStateEnum.SUCCESS == tradeState) {
                        Integer payerTotal = transaction.getAmount().getPayerTotal();
                        if (payerTotal.intValue() == 1) {
                            log.info("业务校验通过，处理核心业务");
                            //5.TODO 核心业务处理:更新本地交易记录
                            paymentInfoService.updatePaymentInfo(transaction);
                        }
                    }
                } catch (Exception e) {
                    //核心业务处理异常，触发全局事务回滚，删除key,让微信再次回调商户系统
                    redisTemplate.delete(key);
                    throw new RuntimeException(e);
                }
            }
        }

    }
}
